package com.example.zz.example;

import android.content.Context;
import android.content.Intent;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author: zhuozhang6
 * @date: 2021/12/8
 * @email: zhuozhang6@iflytek.com
 * @Description:
 */
public class AppCrashHandler implements Thread.UncaughtExceptionHandler {

    private Context mAppContext;
    private volatile boolean isCrashing;
    private DateFormat mFormatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private static AppCrashHandler mAppCrashHandler;

    public static synchronized AppCrashHandler getInstance() {
        if (mAppCrashHandler == null) {
            synchronized (AppCrashHandler.class) {
                if (mAppCrashHandler == null) {
                    mAppCrashHandler = new AppCrashHandler();
                }
            }
        }
        return mAppCrashHandler;
    }

    /**
     * 初始化
     */
    public void init(Context context) {
        isCrashing = false;
        mAppContext = context.getApplicationContext();
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 处理异常逻辑
     */
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (isCrashing) {
            return;
        }
        isCrashing = true;
        e.printStackTrace();
        if (!handleException(e) && mDefaultHandler != null) {
            mDefaultHandler.uncaughtException(t, e);
        }
        kill();
    }

    /**
     * 异常退出应用程序
     */
    private void kill() {
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    }

    /**
     * 是否处理异常
     */
    private boolean handleException(Throwable e) {
        if (e == null) {
            return false;
        }
        try {
            String message = getExceptionMessage(e);
            save2SDCard(message);
            startCrashActivity();
        } catch (Exception ex) {
            return false;
        }
        return true;
    }

    /**
     * 获取异常信息
     */
    private String getExceptionMessage(Throwable e) {
        PrintWriter pw = null;
        Writer writer = new StringWriter();
        try {
            pw = new PrintWriter(writer);
            e.printStackTrace(pw);
        } catch (Exception ex) {
            return "Get exception message fail";
        } finally {
            if (pw != null) {
                pw.close();
            }
        }
        return writer.toString();
    }

    /**
     * 将异常信息写入SD卡，默认崩溃日志存储在/storage/emulated/0/Android/data/com.example.zz.example/files/crashLog
     */
    private void save2SDCard(String message) {
        try {
            String exceptionTime = mFormatter.format(new Date());
            String logPath = mAppContext.getExternalFilesDir("crashLog").getAbsolutePath();
            File dir = new File(logPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            FileOutputStream fos = new FileOutputStream(logPath + "/" + exceptionTime + ".txt");
            fos.write(message.getBytes());
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 崩溃后，重新进入主界面
     */
    private void startCrashActivity() {
        Intent intent = new Intent();
        intent.setClass(mAppContext, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mAppContext.startActivity(intent);
    }
}